using System;
using UnityEngine;
using UnityEngine.UI;

namespace UnityX
{
    /// <summary>
    /// 剪裁图片显示成扇形，开始结束角度以顺时针计算
    /// </summary>
    [DisallowMultipleComponent]
    [RequireComponent(typeof(CanvasRenderer))]
    [AddComponentMenu("UI/UnityX/Image Sector")]
    public class ImageSector : MaskableGraphic
    {
        public enum BorderShape
        {
            Rectangle,
            Circle,
        }

        [SerializeField]
        protected Texture m_Texture;

        [Range(-360, 360)]
        [SerializeField]
        protected float m_BeginAngle = 0;
        [Range(-360, 360)]
        [SerializeField]
        protected float m_EndAngle = 360;
        [SerializeField]
        protected BorderShape m_BorderShape = BorderShape.Circle;
        [Range(12, 360)]
        [SerializeField]
        protected int m_VertCount = 60;

        public override Texture mainTexture
        {
            get
            {
                if (m_Texture == null)
                {
                    if (material != null && material.mainTexture != null)
                    {
                        return material.mainTexture;
                    }
                    return s_WhiteTexture;
                }
                return m_Texture;
            }
        }
        public Texture texture
        {
            get
            {
                return m_Texture;
            }
            set
            {
                if (m_Texture == value)
                    return;
                m_Texture = value;
                SetVerticesDirty();
                SetMaterialDirty();
            }
        }
        /// <summary>
        /// 开始结束角度以顺时针计算
        /// </summary>
        public float beginAngle { get => m_BeginAngle; set { m_BeginAngle = value; SetVerticesDirty(); } }
        /// <summary>
        /// 开始结束角度以顺时针计算
        /// </summary>
        public float endAngle { get => m_EndAngle; set { m_EndAngle = value; SetVerticesDirty(); } }
        public BorderShape borderShape { get => m_BorderShape; set { m_BorderShape = value; SetVerticesDirty(); } }
        public int vertCount { get => m_VertCount; set { m_VertCount = value; SetVerticesDirty(); } }

        protected ImageSector()
        {
            useLegacyMeshGeneration = false;
        }
        protected override void OnPopulateMesh(VertexHelper vh)
        {
            vh.Clear();
            switch (m_BorderShape)
            {
                case BorderShape.Rectangle:
                    RectangleMesh(vh);
                    break;
                case BorderShape.Circle:
                    CircleMesh(vh);
                    break;
                default:
                    break;
            }
        }
        private void RectangleMesh(VertexHelper vh)
        {
            if (m_BeginAngle >= m_EndAngle)
            {
                return;
            }

            Rect rect = GetPixelAdjustedRect();
            Color32 color = this.color;
            if (m_EndAngle - m_BeginAngle >= 360)
            {
                vh.AddVert(new Vector3(rect.x, rect.y), color, new Vector2(0, 0));
                vh.AddVert(new Vector3(rect.x, rect.y + rect.height), color, new Vector2(0, 1));
                vh.AddVert(new Vector3(rect.x + rect.width, rect.y + rect.height), color, new Vector2(1, 1));
                vh.AddVert(new Vector3(rect.x + rect.width, rect.y), color, new Vector2(1, 0));
                vh.AddTriangle(0, 1, 2);
                vh.AddTriangle(0, 2, 3);
                return;
            }

            float rx = rect.width / 2;
            float ry = rect.height / 2;
            float cx = rect.x + rx;
            float cy = rect.y + ry;
            float a1 = m_BeginAngle % 360;
            float a2 = m_EndAngle % 360;

            //中心点
            vh.AddVert(new Vector3(cx, cy), color, new Vector2(0.5f, 0.5f));

            //
            float v1 = (float)Math.Tan(a1 * Math.PI / 180);
            if ((a1 > -45 && a1 < 45) || a1 <= -315)
                vh.AddVert(new Vector3(rx * v1 + cx, rect.y + rect.height), color, new Vector2((v1 + 1) / 2, 1));
            else if ((a1 > 45 && a1 < 135) || (a1 > -315 && a1 < -225))
                vh.AddVert(new Vector3(rect.x + rect.width, ry * v1 + cy), color, new Vector2(1, 1));
            else if ((a1 > 135 && a1 < 225) || (a1 > -225 && a1 < -135))
                vh.AddVert(new Vector3(rx * v1 + cx, rect.y), color, new Vector2((v1 + 1) / 2, 1));
            else if ((a1 > 225 && a1 < 315) || (a1 > -135 && a1 < -45))
                vh.AddVert(new Vector3(rect.x, rect.y + rect.height), color, new Vector2(0, 1));

            for (float a = m_BeginAngle + 90; a < m_EndAngle; a += 90)
            {
                if ((a >= -45 && a < 45) || a < -315)
                    vh.AddVert(new Vector3(rect.x, rect.y + rect.height), color, new Vector2(0, 1));
                else if ((a >= 45 && a < 135) || (a >= -315 && a < -225))
                    vh.AddVert(new Vector3(rect.x + rect.width, rect.y + rect.height), color, new Vector2(1, 1));
                else if ((a >= 135 && a < 225) || (a >= -225 && a < -135))
                    vh.AddVert(new Vector3(rect.x + rect.width, rect.y), color, new Vector2(1, 0));
                else if ((a >= 225 && a < 315) || (a >= -135 && a < -45))
                    vh.AddVert(new Vector3(rect.x, rect.y), color, new Vector2(0, 0));
            }

            //double v2 = Math.Tan(a2);
            //if ((a2 > -45 && a2 < 45) || a2 <= -315)
            //    t2 = 0;
            //else if ((a2 > 45 && a2 < 135) || (a2 > -315 && a2 < -225))
            //    t2 = 1;
            //else if ((a2 > 135 && a2 < 225) || (a2 > -225 && a2 < -135))
            //    t2 = 2;
            //else if ((a2 > 225 && a2 < 315) || (a2 > -135 && a2 < -45))
            //    t2 = 3;

            //面
            for (int i = 1; i < vh.currentVertCount - 1; i++)
            {
                vh.AddTriangle(0, i, i + 1);
            }
        }
        private void CircleMesh(VertexHelper vh)
        {
            if (m_BeginAngle >= m_EndAngle)
            {
                return;
            }
            Rect rect = GetPixelAdjustedRect();
            Color32 color = this.color;
            float rx = rect.width / 2;
            float ry = rect.height / 2;
            float cx = rect.x + rx;
            float cy = rect.y + ry;
            double gap = Math.PI * 2 / m_VertCount;
            //中心点
            vh.AddVert(new Vector3(cx, cy), color, new Vector2(0.5f, 0.5f));
            //满圆
            if (m_EndAngle - m_BeginAngle >= 360)
            {
                //外围点
                for (int i = 0; i < m_VertCount; i++)
                {
                    float x = (float)Math.Cos(i * gap);
                    float y = (float)Math.Sin(i * gap);
                    vh.AddVert(new Vector3(rx * x + cx, ry * y + cy), color, new Vector2((x + 1) / 2, (y + 1) / 2));
                }
                //面
                for (int i = 1; i < m_VertCount; i++)
                {
                    vh.AddTriangle(0, i, i + 1);
                }
                vh.AddTriangle(0, m_VertCount, 1);
                return;
            }

            double a1 = (m_BeginAngle - 90) * Math.PI / 180;
            double a2 = (m_EndAngle - 90) * Math.PI / 180;
            //外围点
            for (double i = a1; i < a2; i += gap)
            {
                float x = (float)Math.Cos(i);
                float y = -(float)Math.Sin(i);
                vh.AddVert(new Vector3(rx * x + cx, ry * y + cy), color, new Vector2((x + 1) / 2, (y + 1) / 2));
            }
            //最后一个点
            {
                float x = (float)Math.Cos(a2);
                float y = -(float)Math.Sin(a2);
                vh.AddVert(new Vector3(rx * x + cx, ry * y + cy), color, new Vector2((x + 1) / 2, (y + 1) / 2));
            }
            //面
            for (int i = 1; i < vh.currentVertCount - 1; i++)
            {
                vh.AddTriangle(0, i, i + 1);
            }
        }

        protected override void OnDidApplyAnimationProperties()
        {
            SetMaterialDirty();
            SetVerticesDirty();
            SetRaycastDirty();
        }
    }
}